package de.jmda.mview.fx.node.typeshape.relation;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Point2D;
import javafx.scene.input.MouseEvent;
import de.jmda.fx.node.Line;
import de.jmda.fx.node.behaviour.BehaviourMouseDraggingStop;
import de.jmda.fx.node.behaviour.DraggingData;

/**
 * Simple relation segment that connects {@link Line#startPointProperty()} and
 * {@link Line#endPointProperty()} with a horizontal line.
 *
 * @author roger.jmda@gmail.com
 */
public class RelationSegmentHorizontal extends RelationSegmentOrthogonal
{
	/**
	 * @param start observable starting point for relation segment
	 * @param xEndProvider observable point providing x coordinate of end point
	 *                     for relation segment
	 */
	public RelationSegmentHorizontal(
			ObjectProperty<Point2D> start, ObjectProperty<Point2D> xEndProvider)
	{
		super(
				start,
				new SimpleObjectProperty<Point2D>(
						new Point2D(xEndProvider.get().getX(), start.get().getY())));
		
		start.addListener(new StartPointUpdater<Point2D>());
		xEndProvider.addListener(new EndPointUpdater<Point2D>());
	}

	@Override
	public void activateDragging()
	{
		BehaviourMouseDraggingData behaviourMouseDraggingData =
				new BehaviourMouseDraggingData();
		new BehaviourMouseDraggingStartLine(     this, behaviourMouseDraggingData);
		new BehaviourMouseDraggingStop(          this, behaviourMouseDraggingData);
		new BehaviourMouseDraggingLineHorizontal(this, behaviourMouseDraggingData);
	}

	private class StartPointUpdater<T extends Point2D>
			implements ChangeListener<Point2D>
	{
		/**
		 * Updates start coordinates of segment with coordinates of <code>newValue
		 * </code>. Also synchronizes end y coordinate of segment with new start y
		 * coordinate.
		 *
		 * @see javafx.beans.value.ChangeListener#changed(javafx.beans.value.ObservableValue, java.lang.Object, java.lang.Object)
		 */
		@Override
    public void changed(ObservableValue<? extends Point2D> observable,
        Point2D oldValue, Point2D newValue)
    {
			setStartX(newValue.getX());
			setStartY(newValue.getY());

			setEndY(getStartY());
    }
	}
	
	private class EndPointUpdater<T extends Point2D>
			implements ChangeListener<Point2D>
	{
		/**
		 * Updates end x coordinate of segment with x coordinate of <code>newValue
		 * </code>.
		 *
		 * @see javafx.beans.value.ChangeListener#changed(javafx.beans.value.ObservableValue, java.lang.Object, java.lang.Object)
		 */
		@Override
    public void changed(ObservableValue<? extends Point2D> observable,
        Point2D oldValue, Point2D newValue)
    {
			setEndX(newValue.getX());
    }
	}

	public class BehaviourMouseDraggingLineHorizontal
			extends BehaviourMouseDraggingLine
	{
		public BehaviourMouseDraggingLineHorizontal(
				Line line, BehaviourMouseDraggingData behaviourMouseDraggingData)
    {
	    super(line, behaviourMouseDraggingData);
    }

		/**
		 * Sets new y coordinates to line, allows vertical movement, prohibits
		 * horizontal movement. 
		 *
		 * @see de.jmda.fx.node.Line.BehaviourMouseDraggingLine#showBehaviour(javafx.scene.input.MouseEvent)
		 */
		@Override
	  public void showBehaviour(MouseEvent mouseEventCurrent)
	  {
			DraggingData lineDraggingData =
					getLineDraggingData(
							mouseEventCurrent, line, behaviourMouseDraggingData);

			double startPointY = line.getStartPoint().getY() + lineDraggingData.getDragY();
			double endPointY   = line.getEndPoint().getY()   + lineDraggingData.getDragY();

			// set line start and end y coordinates to new values
			line.setStartY(startPointY);
			line.setEndY(    endPointY);
			
			behaviourMouseDraggingData.setMouseDragging(mouseEventCurrent);
	  }
	}
}